#include <cstdio>
#include <cstdlib>
#include "vectclasses.hpp"
#include "outputclasses.hpp"
#include "classifyclasses.hpp"


void Output::PrintGeneral(Vector classresult)
{
	FILE *fout;
	fout = fopen("output.txt","wt");
    int vectnum = classresult.getLength();
	for (int i = 0; i < vectnum; i++)
	{
		fprintf(fout, "Vector number %d belongs to the class number %d\n", i, classresult.at(i));
	}
    fclose(fout);
}

inline void endian_swap(unsigned short& x)
{
    x = (x>>8) |
        (x<<8);
}

inline void endian_swap(unsigned int& x)
{
    x = (x>>24) |
        ((x<<8) & 0x00FF0000) |
        ((x>>8) & 0x0000FF00) |
        (x<<24);
}

void Output::PrintDigits(VectorArray * inputvect, VectorArray * kernel, int teacher)
{
    int mydigits = inputvect->getVectNumber();
	Vector correctclasses(10);
	Vector myclasses(10);
	VectorArray intersectclasses(10, 10);
	for (int i = 0; i < 10; i++)
	{
	    correctclasses.at(i) = 0;
	    myclasses.at(i) = 0;

	    for (int j = 0; j < 10; j++)
	    {
	        intersectclasses.at(i,j) = 0;
	    }
	}
	int correctresult = -1;
	int myresult = -1;
    double errors = 0;
    unsigned int magicnum = 0;
    unsigned int digitnum;
    unsigned int rows;
    unsigned int cols;

    FILE * flabels = fopen("train-labels.idx1-ubyte", "rb");
    if (flabels == NULL)
    {
        printf("Can't open labels file.\n");
        return;
    }
    fread(&magicnum, 4, 1,flabels);
    endian_swap(magicnum);
    printf("magicnum %d\n", magicnum);
    fread(&digitnum, 4, 1,flabels);
    endian_swap(digitnum);
    printf("digitnum %d\n", digitnum);
    char * labels = new char[mydigits];
    for (int i = 0; i < mydigits; i++)
    {
        fread(&(labels[i]), 1, 1, flabels);
    }
    fclose(flabels);
    FILE *fanswers;
    fanswers = fopen("answers.txt", "wt");
    for (int i = 0; i < mydigits; i++)
    {
        fprintf(fanswers, "Vector number %d belongs to the class number %d\n", i, (int)(labels[i]));
    }
    fclose(fanswers);

	//Draw::drawClasses(pixelclasses);

	for (int i = 0; i < mydigits; i++)
	{
	    myresult = Classify::classifyOne(inputvect->getVector(i), *kernel);
	    correctresult = (int)labels[i];
	    if (myresult != correctresult)
	    {
	        ++errors;
	    }
	    ++correctclasses.at(correctresult);
        ++myclasses.at(myresult);
        ++(intersectclasses.at(myresult, correctresult));
	}

	FILE *fstats;
	if (teacher == 0)
	{

        fstats = fopen("result_statistics_without_teaching.txt", "wt");
	    Vector recall(10);
	    Vector precision(10);
	    Vector fmeasure(10);
	    double errorrate = errors/mydigits;
	    fprintf(fstats, "The error rate is equal to %.2lf%%.\n", 100*errorrate);
	    fprintf(fstats, "class  recall   precision   fmeasure \n");
	    for (int i = 0; i < 10; i++)
	    {
	        recall.at(i) = intersectclasses.at(i,i)/correctclasses.at(i);
	        precision.at(i) = intersectclasses.at(i,i)/myclasses.at(i);
	        fmeasure.at(i) = 2*recall.at(i)*precision.at(i)/(recall.at(i) + precision.at(i));
	        fprintf(fstats, "%d       %.3lf     %.3lf     %.3lf\n", i, recall.at(i), precision.at(i), fmeasure.at(i));
	    }
	}
	else
	{
        fstats = fopen("result_statistics_with_teaching.txt", "wt");
	    double myclasssum = 0;
	    double correctclasssum = 0;
	    double intersectsum = 0;
	    double probcorr = 0;
	    double probmy = 0;
	    Vector vectprobcorr(10);
	    Vector vectprobmy(10);
        for (int i = 0; i < 10; i++)
        {
            vectprobcorr.at(i) = 0;
            vectprobmy.at(i) = 0;
            myclasssum += myclasses.at(i)*myclasses.at(i);
            correctclasssum += correctclasses.at(i)*correctclasses.at(i);
            for (int j = 0; j < 10; j++)
            {
                intersectsum += intersectclasses.at(i,j)*intersectclasses.at(i,j);
                vectprobcorr.at(i) += (intersectclasses.at(i,j)*intersectclasses.at(i,j))/(correctclasses.at(i)*correctclasses.at(i));
                vectprobmy.at(i) += (intersectclasses.at(i,j)*intersectclasses.at(i,j))/(myclasses.at(i)*myclasses.at(i));
            }
        }
        probcorr = intersectsum/correctclasssum;
        probmy = intersectsum/myclasssum;
        fprintf(fstats, "The first probability (P1 = P{exists i: x,y in Ci | exists j: x,y in C'j}) is equal to %.3lf.\n", probcorr);
        fprintf(fstats, "The second probability (P2 = P{exists i: x,y in C'i | exists j: x,y in Cj}) is equal to %.3lf.\n", probmy);
        fprintf(fstats, "class    P1(i)    P2(i) \n");
        for (int i = 0; i < 10; i++)
        {
	        fprintf(fstats, "%d       %.3lf     %.3lf\n", i, vectprobcorr.at(i), vectprobmy.at(i));
	    }
	}
    fclose(fstats);
}

void Output::PrintTexts(Vector classresult, int classnum, char * fnewsname)
{
    int length = classresult.getLength();
    FILE *flines;
    FILE *fnews;
    FILE **fclasses = new FILE*[classnum];
    char mystr[1000];
    flines = fopen("filefinder.txt", "rt");
    int linecount = 0;
    int k = 0;
    int currdoc = 0;
    int * lines;
    lines = new int[length];
    lines[0] = 1;
    for (int i = 1; i < length; i++)
    {
        fscanf(flines, "%d %d", &k, &(lines[i]));
    }
    fclose(flines);
    char filename[30];
    fnews = fopen(fnewsname, "rt");
    for (int i = 0; i < classnum; i++)
    {
        sprintf(filename, "class_%d.txt", i);
        fclasses[i] = fopen(filename, "wt");
    }
    while (!feof(fnews))
    {
        fgets(mystr, 1000, fnews);
        linecount++;
        for (int i = 0; i < length; i++)
        {
            if ((linecount >= lines[i]) && (linecount < lines[i+1]))
            {
                currdoc = i;
                break;
            }
        }
        for (int i = 0; i < classnum; i++)
        {
            if (classresult.at(currdoc) == i)
            {
                fprintf(fclasses[i], "%s", mystr);
                break;
            }
        }

    }
    fclose(fnews);
    for (int i = 0; i < classnum; i++)
    {
        fclose(fclasses[i]);
    }
    delete [] lines;
    delete [] fclasses;
}
